package com.googlecode.continuity.core.server.hibernate;

import java.util.Map;

import org.gwtwidgets.server.spring.GWTHandler;
import org.gwtwidgets.server.spring.GWTRPCServiceExporter;
import org.gwtwidgets.server.spring.ReflectionUtils;
import net.sf.hibernate4gwt.core.HibernateBeanManager;

/**
 * GWTHibernateHandler handles requests to GWT RPC services which send or receive Hibernate controlled objects.  In
 * difference to {@link org.gwtwidgets.server.spring.GWTHandler}, it uses the
 * {@link com.googlecode.continuity.core.server.hibernate.GWTHibernateRPCServiceExporter} to construct a service on
 * server startup.
 *
 * The <code>beanManager</code> property must be set for this handler to work.
 *
 * @author Peter Schmitt <aragos@aragos.de>
 */
public class GWTHibernateHandler extends GWTHandler {
  private HibernateBeanManager beanManager;
  // temporary mapping, void after bean initialisation
  private Map<String, Object> mapping;

  /**
   * Set a new bean manager for this handler.
   *
   * @param beanManager new bean manager
   */
  public void setBeanManager(HibernateBeanManager beanManager) {
    this.beanManager = beanManager;
  }

  /**
   * Invoked automatically by Spring after initialisation, checks for the existence of a HibernateBeanManager and
   * creates the internal service objects.
   */
  public void afterPropertiesSet() throws Exception {
    if (beanManager == null) {
      throw new IllegalStateException("The [beanManager] property must be set.");
    }

    for (Map.Entry<String, Object> entry : mapping.entrySet()) {
      registerHandler(entry.getKey(),
          createServletInstance(entry.getValue(), ReflectionUtils.getExposedInterfaces(entry.getValue()
              .getClass())));
    }
    mapping = null;
  }

  /**
   * Sets a mapping between URLs and services.
   *
   * @param mapping list of url and service pairs
   */
  public void setMappings(Map<String, Object> mapping) {
    this.mapping = mapping;
  }

  /**
   * Creates a new service instance that can be called through its registered URL.
   *
   * todo: rename (servlet->service)/integrate with superclass
   *
   * @param service original service
   * @param serviceInterfaces interfaces the original service implements
   * @return newly constructed service
   */
  protected GWTRPCServiceExporter createServletInstance(Object service, Class[] serviceInterfaces) {
    GWTRPCServiceExporter exporter = new GWTHibernateRPCServiceExporter(beanManager);
    exporter.setServletContext(getServletContext());
    exporter.setService(service);
    exporter.setServiceInterfaces(serviceInterfaces);
    try {
      exporter.afterPropertiesSet();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return exporter;
  }
}
